The CIconButton CDEF is a custom control definition procedure that allows developers to elegantly and simply included “icon buttons” in their applications. These icon buttons are built from one or more cicn resources. The CIconButton CDEF works under System 6 & 7, is sensitive to multiple monitors and monitor depths, and works with or without Color Quickdraw. Mouse tracking is sensitive to the cicn mask, so your buttons don’t have to be rectangular in shape.

The CIconButton CDEF supports the three standard button types:

          Pushbutton: a normal icon button that hilites when you click on it,
          and resets itself when you release the mouse.

          RadioButton: the same as the Pushbutton control, except that it toggles back
          and forth between two icons when you select it. It can also be used as a simple
          toggle switch (e.g. like the key-latch in the Alarm Clock DA).

          CheckBox: shows or hides a third icon depending on its state. This third icon
          is usually a checkmark of some sort.

The CIconButton CDEF uses offscreen graphics to enhance the appearance and behavior of the buttons, and provide very fast drawing speeds. It usually requires a memory overhead of 12-18K per 32 by 32 pixel icon. For the memory conscious, we also provide the CIconButtonLite CDEF which doesn’t cache the icon images: the drawing is slightly slower, but only uses 3-5K per 32 by 32 pixel icon. All of the functionality described below is available in both the CIconButton CDEF and the CIconButtonLite CDEF.

_ Demo App _____________________________________________
This sample application demonstrates most of the features in the CIconButton CDEF. All of the controls in the dialog make use of the API and Library that was provided with this package. The documentation for the API calls follows below.

Some notes about this sample application:

      •  There are four sets of icons you can test out; use the popup menu to switch
          between different sets.
      •  The “Pushbutton” example in the “Grayscale Icons” set is an example of
          the selected-button icon generation that the CIconButton CDEF does.
          Normally, you supply a separate cicn resource for the selected icon. If you don’t,
          as in this case, the CIconButton CDEF will do its best to generate one on the fly.
      •  The “Times 14 Bold, Italic” option is an example of setting the button titles to an
          arbitrary text font, size, style, and drawing mode.

Note: You may notice some flicker if you change several settings (e.g. change the font, title orienation, and switch the icons). This flicker is due to a global realignment of button titles that occurs after every setting you change. The CIconButton CDEF does not make any assumptions about how you want the title aligned (hence the variety settings that you can control); in this demonstration application, however, we adjust each button after every setting switch to reflect the current font settings, title orientation, and the actual icons it is displaying. For example, if you choose the “Times 14 bold, italic” option, we set the font information for all 4 buttons, but also increase the gap between the icon and the text to account for the larger font size (another 4 calls).

This flicker won’t be an issue for you unless you plan to be switching several icons, fonts and title orientations on the fly. If you do plan to do alot of this kind of dynamic switching, we suggest you use an offscreen pixMap or GWorld to do the drawing, and then copy the final screen image to your window when you’re done updating the buttons.

_ Usage ________________________________________________
Most buttons used with the CIconButton CDEF are created from two cicns: the Shell cicn and the Main cicn.

      •  The Shell cicn is a frame which house the Main icon image. The advantage to
          storing the Shell separately is that it saves space, and you can easily produce
          a consistent look and feel to your buttons if they all share the same frame.
      •  The Main cicn holds the iconic picture you want to display in your button. It is
          drawn centered in the Shell (if no Shell is specified, the Main icon is centered
          in the control’s rectangle).
      •  A third icon, the Alternate icon, is used by the RadioButton and CheckBox style
          buttons as the third part of the button. This third part is hidden or shown
          depending on the state of the button. For example, in a CheckBox button, the
          Alternate icon plays the role of the ‘X’ in the box; for a RadioButton, it plays
          the role of the ‘•’ inside the circle.

The CIconButton CDEF reinterprets three fields in the control record as icon ID specifiers. The contrlMin field holds the Main icon ID, the contrlMax field holds the Shell icon ID, and the contrlValue field holds the Alternate icon ID.

You can define a separate set of cicns for normal and hilited buttons. If you want to include a “hilited” version of the icon, include it as the next sequential cicn resource in the resource fork (that is, if your normal cicn is ID 1000, your hilited cicn should be ID 1001). You can specify a custom hilited-icons for any of the Main, Shell, and Alternate icons; CIconButton will dynamically hilight those that don’t have custom hilite-icons.

The icons are loaded in when the control is created, either with NewControl or GetNewControl. After reading in the icons, the CIconButton CDEF resets those fields to the standard off-state for the control, and doesn’t touch them again. At the very least, you should specify the default Main icon to load in; if the CIconButton CDEF cannot read that in during initialization, it will beep to alert you of the fact (but continue on as best it can).

_ Special Drawing Situations _________________________________
There is one issue worth pointing out that concerns the way the control updates itself: when a CDEF receives an update (draw) event, it assumes that the background is already correctly drawn. Normally, this isn’t a problem, since a CDEF usually overwrites the same screen region. For the CIconButton CDEF, however, this can be tricky because of the API calls that allow you to change its geometry on the fly (e.g. change the title from being below the button to being to the right, or the Latch button that toggles between a vertical state and horizontal state depending on whether the mouse is inside or outside of the button). The CIconButton CDEF has no way of knowing what image underlies the control, so it cannot always effectively “erase” itself before drawing.

We solve this by providing (1) a callback to allow you to redraw the background image, and (2) a DynamicGeometry flag to let the CIconButton CDEF know it is dealing with one of these special situations.

_ The API Routines ________________________________________
You can modify the icon IDs and other settings of a CIconButton control using the routines provided in the CIconButton.lib file. These routines are described below, and their headers can be found in CIconButton.Lib.Intf.p.

PROCEDURE CIB_SetUseWFont (c: ControlHandle; useWFont: boolean);
Determines whether the title is displayed in the window’s font, style and size, or uses the standard System font and size (usually Chicago 12pt plain).

PROCEDURE CIB_SetDynamicGeometry (c: ControlHandle; GeometryChanges: boolean);
Determines how the CIconButton CDEF erases its box when updating. The default setting for the DynamicGeometry flag is false: erase the icon mask before drawing using the current background color and pattern. This should be all you need in most cases (including buttons on non-white backgrounds)

If your button’s geometry changes while tracking the mouse (like the Latch button), the control needs not only to erase the area it will draw to, but erase its old position as well. In this case, the DynamicGeometry flag should be true.

PROCEDURE CIB_SetCallbackProc (c: ControlHandle; theProc: procPtr);
Sets the draw procedure that  should use to erase its background. Use this if you’ve got a complex background and your button changes geometry (in the example application, the Latch button uses this to redraw the patterned gray background). The procedure receives a handle to the control, and the rect it should draw into. Here’s the one used by the sample application:

PROCEDURE UpdateRoutine (c: controlHandle; r: rect);
   BEGIN
      foreColor(yellowColor);
      FillRect(r, gray);
      foreColor(blackColor);
   END;

PROCEDURE CIB_SetTitleOrientation (c: ControlHandle; orientation: integer);
Determines where the title is positioned relative to the icon. Use the following constants (taken from the System 7 icon family definitions):

  atTop = $2;
  atBottom = $3;
  atLeft = $8;
  atRight = $C;

You can hide the title by setting it to the empty string via the toolbox SetCTitle call.

PROCEDURE CIB_SetTrackRegion (c: ControlHandle; TrackRegion: boolean);
Determines whether the CIconButton CDEF tracks the mouse in the icon region or across the whole control rectangle. This is useful for small icons that may be hard to click on (e.g. the latch button).

PROCEDURE CIB_SetMainIcon (c: ControlHandle; iconID: integer);
PROCEDURE CIB_SetShellIcon (c: ControlHandle; iconID: integer);
PROCEDURE CIB_SetAltIcon (c: ControlHandle; iconID: integer);
These calls allow you to set or reset the icon IDs for a given button. If you pass 0 into the iconID parameter, that icon won’t be drawn.

PROCEDURE CIB_SetIcons (c: ControlHandle; main, shell, alt: integer);
This lets you do the same thing as the three procedures listed above, but lets you set all three icon IDs at once.

PROCEDURE CIB_SetLabelGap (c: ControlHandle; gap: integer);
Sets the distance between the Shell (or Main) icon and the button label for checkmark buttons.

PROCEDURE CIB_SetCheckmarkGap (c: ControlHandle; gap: integer);
Sets the distance between the Main icon and the Alternate icon for checkmark buttons.

PROCEDURE CIB_SetTextFont (c: ControlHandle; theFont: integer);
Sets the text font for the control. Use the toolbox GetFNum call to translate a font name to a number in order to use this routine. If you pass in 0, the control will be displayed in the System font, or in the Window font if the “UseWFont” flag has been set (using CIB_SetUseWFont).

PROCEDURE CIB_SetTextFace (c: ControlHandle; theFace: Style);
Sets the text face (or style) for the control. If you pass in 0, the control will be displayed in the System font’s textface, or in the Window’s text face if the “UseWFont” flag has been set (using CIB_SetUseWFont).

PROCEDURE CIB_SetTextSize (c: ControlHandle; theSize: integer);
Sets the text size for the control. If you pass in 0, the control will be displayed in the default System font size, or in the Window font if the “UseWFont” flag has been set (using CIB_SetUseWFont).

PROCEDURE CIB_SetTextMode (c: ControlHandle; theMode: integer);
Sets the text mode for the control. If you pass in 0, the control will be reset to the system mode (srcCopy). Note that the default mode will write black text into a white box, regardless of the current background color or pattern. If you want the button text to lie on top of a background color or image, use srcOr.

PROCEDURE CIB_SetTextState (c: ControlHandle; theTextState: textStatePtr);
Sets the text font, face, size and mode for the control. This is a shortcut call to use if you want to set all of these parameters at once (note that after each of these calls, the button redraws itself; thus if you used 4 separate calls rather than this single call, you would get a slight flicker as the button draws itself 4 times). The routine accepts a pointer to a textState record, defined as follows:

   TextState = PACKED RECORD
      tsFont: integer;
      filler: byte;
      tsFace: Style;
      tsMode: integer;
      tsSize: integer;
    END;
    TextStatePtr = ^TextState;

You should ensure that your compiler treats integers as 2 bytes, and a style type as 1 byte long (the whole record should be 8 bytes).

The CIconButton CDEF also supports several other messages that all defProcs from Digital Alchemy support. They are as follows:

FUNCTION CIB_IsCustomControl (c: ControlHandle): boolean;
Returns true if the defProc is a custom one designed by Digital Alchemy. This routine essentially checks a “author code” embedded inside the defProc.

FUNCTION CIB_GetCopyright (c: ControlHandle): str255;
Returns a copyright string for inclusion in manuals and About boxes. If you are using this defProc in a freeware or shareware program, this text should appear along with your other credits (usually in the About box).

FUNCTION CIB_GetVersion (c: ControlHandle): longint;
Returns the version info for the defProc. This is the same format as the “short version” information as normally stored in a ‘vers’ resource.

_ Licensing and Distribution _________________________________
CIconButton CDEF is ©1993 Ramon M. Felciano, All Rights Reserved. The distribution package may be copied and distributed freely as long as no modifications are made to it and nothing is charged for it. The CDEF must be licensed for use in any software project according to the terms set forth below.

Usage of the object code (CDEF) in software is subject to a licensing fee of $50.00 for a single-product license ($25.00 for shareware/in-house software), or $300.00 for a multiple-product license. The single-product licensing fee is waived for non-commercial, in-house software, or software with a list price of under $100.00, provided you credit CIconButton and Digital Alchemy in the About box, and send us a copy of the software. “About” box credit should read:

                  CIconButton CDEF from Digital Alchemy
             ©1993 Ramon M. Felciano, All Rights Reserved

Source code is available for support purposes for $300.00. Source code is provided as a support material only in order to allow developers to debug problems as quickly as possible. It is not provided as sample code. All code and derivative works thereof remain copyrighted by Ramon M. Felciano.

The fees are additive: if you pay for 6 single-product licenses at $50.00, you will effectively be upgraded to get the multiple-product license. The table below summarizes the licensing scheme:

      Single-product, with software exhange & © credit                                $0.00
 
      Single-product, in-house or shareware                                               $25.00
      Single-product                                                                                         $50.00
      Multiple-product                                                                               $300.00
      Pascal source code                                                                              $300.00

License pricing is subject to change without notice.

Please send any comments, suggestions or bug reports to me at one of the addresses listed below:

      Internet                  felciano@summit.stanford.edu
      America Online     felciano@summit.stanford.edu
      Applelink               felciano@summit.stanford.edu@internet#
      Compuserve           >INTERN:felciano@summit.stanford.edu

Digital Alchemy
P.O.Box 9632
Stanford, CA 94309-9632